package main

import (
	"context"
	"fmt"
	"github.com/coreos/etcd/clientv3"
	"time"
)

//对key增加一个过期时间，这这情况在实现分布式的乐观锁很常用。比如一台机器挂了，这个机器上的锁需要释放。所以锁需要生命期管理
func main() {

	var (
		config             clientv3.Config
		client             *clientv3.Client
		err                error
		lease              clientv3.Lease
		leaseGrantResponse *clientv3.LeaseGrantResponse

		putResponse *clientv3.PutResponse
		getResponse *clientv3.GetResponse

		aliveResponses *clientv3.LeaseKeepAliveResponse

		// 自动续期的只读channel ，写入是etcd的sdk写入
		aliveResponsesChan <-chan *clientv3.LeaseKeepAliveResponse

		kv clientv3.KV
	)

	config = clientv3.Config{
		Endpoints:   []string{"10.70.30.73:2379"},
		DialTimeout: 3 * time.Second,
	}

	if client, err = clientv3.New(config); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("hello,etcd  ")

	kv = clientv3.NewKV(client)
	lease = clientv3.NewLease(client)

	if leaseGrantResponse, err = lease.Grant(context.TODO(), 10); err != nil {
		fmt.Println(err)
		return
	}

	leaseID := leaseGrantResponse.ID
	fmt.Println("首次签订成功，租约号为:", leaseID)

	//key 与lease Id 关联，用option的WithLease，一般情况是为了程序异常或者机器挂掉，防止锁一直被占用。一般情况是定时续租。分别调用keepAlive 或者keepAliveOnce，后台将会起一个协程

	//5秒后会自动取消的context，之前第一次是10秒，5秒一直续着，应该是一秒一次，所以一共15秒的生命周期，比如租房先签合同一个月，然后按天续约
	cxtWithTimeout, _ := context.WithTimeout(context.TODO(), 5*time.Second)

	//演示租约为10秒，5秒后传递取消这个context。导致租约无效,详见末尾输出
	if aliveResponsesChan, err = lease.KeepAlive(cxtWithTimeout, leaseID); err != nil {
		fmt.Println(err)
		return
	}

	//正常的租约（传递的context为非过期的）
	//if aliveResponsesChan, err = lease.KeepAlive(context.TODO(), leaseID); err != nil {
	//	fmt.Println(err)
	//	return
	//}

	// 续约成功，会启动一个协程发心跳给etcd，我们需要去消费这个channel
	go func() {
		for {
			select {
			case aliveResponses = <-aliveResponsesChan:
				if aliveResponses == nil {
					//sdk与etcd之间心跳异常（因为channel里收到了nil），这时候租约就无效了,比如长时间没有应答，或者主动将context cancel，也会导致租约无效，5秒后会自动取消的context见上文

					fmt.Println("租约无效")
					goto END
				} else {
					fmt.Println("=========keep alive正常，从aliveResponsesChan中收到的租约id为: ", aliveResponses.ID, "ttl为：", aliveResponses.TTL)
				}
			}
		}
	END:
	}()

	if putResponse, err = client.KV.Put(context.TODO(), "/cron/lock/job1", "value", clientv3.WithLease(leaseID)); err != nil {
		fmt.Println(err)
		return
	} else {
		fmt.Println("写入成功", putResponse.Header.String())
	}

	// 检查key是否过期
	for {
		if getResponse, err = kv.Get(context.TODO(), "/cron/lock/job1"); err != nil {
			fmt.Println(err)
			return
		} else {
			if getResponse.Count == 0 {
				fmt.Println("已经过期，结束")
				break
			} else {
				fmt.Println("还没过期,过1s再看你", getResponse.Kvs)
				time.Sleep(1 * time.Second)
			}
		}
	}
	//正常情况输出如下
	//hello,etcd
	//首次签订成功，租约号为: 7587845480017428980
	//=========keep alive正常，从aliveResponsesChan中收到的租约id为:  7587845480017428980 ttl为： 10
	//写入成功 cluster_id:14841639068965178418 member_id:10276657743932975437 revision:127 raft_term:3
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//=========keep alive正常，从aliveResponsesChan中收到的租约id为:  7587845480017428980 ttl为： 10
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//=========keep alive正常，从aliveResponsesChan中收到的租约id为:  7587845480017428980 ttl为： 10
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//=========keep alive正常，从aliveResponsesChan中收到的租约id为:  7587845480017428980 ttl为： 10
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//=========keep alive正常，从aliveResponsesChan中收到的租约id为:  7587845480017428980 ttl为： 10
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//=========keep alive正常，从aliveResponsesChan中收到的租约id为:  7587845480017428980 ttl为： 10
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]
	//还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:127 mod_revision:127 version:1 value:"value" lease:7587845480017428980 ]

	//5秒过期输出如下
	//	hello,etcd
	//	首次签订成功，租约号为: 7587845480017429005
	//	=========keep alive正常，从aliveResponsesChan中收到的租约id为:  7587845480017429005 ttl为： 10
	//	写入成功 cluster_id:14841639068965178418 member_id:10276657743932975437 revision:129 raft_term:3
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	=========keep alive正常，从aliveResponsesChan中收到的租约id为:  7587845480017429005 ttl为： 10
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	租约无效
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	还没过期,过1s再看你 [key:"/cron/lock/job1" create_revision:129 mod_revision:129 version:1 value:"value" lease:7587845480017429005 ]
	//	已经过期，结束
	//
	//	Process finished with exit code 0
}
